using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace ShootThemUp.Sources.PlayerInputs.WindowsPhone
{
    /// <summary>
    /// This class determines the player actions and movements in function of the windows phone statement.
    /// The movements are determined by the accelerometer.
    /// </summary>
    public class AccelerometerInput : WindowsPhonePlayerInput
    {
        #region Constant Fields

        /// <summary>
        /// The default x position of the accelerometer. If the accelerometer is in this position, the ship don't move.
        /// </summary>
        private const float DEFAULT_ACCELEROMETER_X_VALUE = 0;
        /// <summary>
        /// The default y position of the accelerometer. If the accelerometer is in this position, the ship don't move.
        /// </summary>
        private const float DEFAULT_ACCELEROMETER_Y_VALUE = -0.5F;
        /// <summary>
        /// The factor of the accelerometer positions.
        /// </summary>
        private const float ACCEL_FACTOR = 2;
        /// <summary>
        /// This value defined an interval between the center point ( here x=0, y=-0.5), in this interval (x= +/- value, y= -0.5 +/- value) the ship don't move.
        /// </summary>
        private const float STABILIZATION_VALUE = 0.04f;

        #endregion

        #region Fields

        private Accelerometer accelerometerSensor;
        /// <summary>
        /// This vector 2D is used to store the data of the accelerometer.
        /// </summary>
        private Vector2 accelerometer2DValue = Vector2.Zero;
        private bool accelerometerIsActive = false;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="AccelerometerInput"/> class.
        /// </summary>
        public AccelerometerInput()
        {
            accelerometerSensor = new Accelerometer();

            // Add the accelerometer event handler to the accelerometer sensor.
            accelerometerSensor.ReadingChanged += new EventHandler<AccelerometerReadingEventArgs>(AccelerometerValuesChanged);

            this.StartAccelerometer();
        }

        #endregion

        #region Inherited Methods

        /// <summary>
        /// Speeds of the player ship, in function of the specified time elapsed and the accelerometer state.
        /// </summary>
        /// <returns>
        /// The new speed of the player, depending of the player inputs.
        /// </returns>
        public override Vector2 Speed()
        {
            float x = accelerometer2DValue.X;
            float y = accelerometer2DValue.Y;

            if (Math.Abs(x - AccelerometerInput.DEFAULT_ACCELEROMETER_X_VALUE) < AccelerometerInput.STABILIZATION_VALUE)
                x = AccelerometerInput.DEFAULT_ACCELEROMETER_X_VALUE;

            if (Math.Abs(y - AccelerometerInput.DEFAULT_ACCELEROMETER_Y_VALUE) < AccelerometerInput.STABILIZATION_VALUE)
                y = AccelerometerInput.DEFAULT_ACCELEROMETER_Y_VALUE;

            return new Vector2(( x - AccelerometerInput.DEFAULT_ACCELEROMETER_X_VALUE) * AccelerometerInput.ACCEL_FACTOR, - (y - AccelerometerInput.DEFAULT_ACCELEROMETER_Y_VALUE) * AccelerometerInput.ACCEL_FACTOR);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Starts the accelerometer.
        /// </summary>
        public void StartAccelerometer()
        {
            // Start the accelerometer
            try
            {
                accelerometerSensor.Start();
                accelerometerIsActive = true;
            }
            catch (AccelerometerFailedException)
            {
                // the accelerometer couldn't be started.
                accelerometerIsActive = false;
            }
            catch (UnauthorizedAccessException)
            {
                // This exception is thrown in the emulator-which doesn't support an accelerometer.
                accelerometerIsActive = false;
            }
        }

        /// <summary>
        /// Stops the accelerometer.
        /// </summary>
        public void StopAccelerometer()
        {
            // Stop the accelerometer if it's active.
            if (accelerometerIsActive)
            {
                try
                {
                    accelerometerSensor.Stop();
                    accelerometerIsActive = false;
                }
                catch (AccelerometerFailedException)
                {
                    // the accelerometer couldn't be stopped now.
                }
            }
        }

        #endregion

        #region Handlers

        /// <summary>
        /// Handler of the accelerometer events.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The <see cref="Microsoft.Devices.Sensors.AccelerometerReadingEventArgs"/> instance containing the event data.</param>
        public void AccelerometerValuesChanged(object sender, AccelerometerReadingEventArgs e)
        {
            accelerometer2DValue.X = (float)e.X;
            accelerometer2DValue.Y = (float)e.Y;
        }

        #endregion
    }
}
